import MD5 from 'md5'
import { NUMBERS, LOWER_CASE_CHARS, UPPER_CASE_CHARS, NORMAL_PUNCTUATION } from '@/js/constants'

export function genRandomStr(len = 16, chars = null) {
  const defaultChars = [].concat(NUMBERS, LOWER_CASE_CHARS, UPPER_CASE_CHARS)
  const charArr = chars || defaultChars
  let str = ''
  for (let i = 0; i < len; i += 1) {
    str += charArr[Math.floor(Math.random() * charArr.length)]
  }
  return str
}

function genStrRecursive(len) {
  let result = ''
  return function genStr(toBeMD5Str, isNumber = true) {
    const md5Str = MD5(toBeMD5Str)
    const regx = isNumber ? new RegExp(/\D/, 'g') : new RegExp(/\d/, 'g')
    const replacedStr = md5Str.replace(regx, '')
    result += replacedStr
    if (result.length < len) {
      return genStr(replacedStr, isNumber)
    }
    return result.substr(0, len)
  }
}

function genIndexFromMD5(str, len, isReverse = false) {
  const handledStr = isReverse ? str.split('').reverse().join('') : str
  return genStrRecursive(len)(handledStr, true)
}

export function calcPassword({ account, hid, len, type, remoteMasterCode, localMasterCode }) {
  // number n
  // char c
  // punctuation p
  const passwordOrder = []
  if (type.includes('number')) {
    passwordOrder.push('n')
  }
  if (type.includes('char')) {
    passwordOrder.push('c')
  }
  if (type.includes('punctuation')) {
    passwordOrder.push('p')
  }
  const passwordOrderLen = passwordOrder.length

  const encodeStr = `${localMasterCode}${account}${hid}${remoteMasterCode}`
  const passwordOrderIndex = genIndexFromMD5(encodeStr, len)
  let password = ''
  for (let i = 0; i < len; i += 1) {
    const char = passwordOrderIndex[i] % passwordOrderLen
    password += passwordOrder[char]
  }

  const numbers = genStrRecursive(len)(encodeStr, true).split('')
  let chars = genStrRecursive(len)(encodeStr, false).split('')
  chars = chars.map((c, i) => (+numbers[i] % 2 === 0 ? c : c.toUpperCase()))
  const punctuationLen = NORMAL_PUNCTUATION.length
  const punctuationIndex = genStrRecursive(len * 2)(encodeStr, true).match(/.{2}/g).map(pi => +pi % punctuationLen)
  const punctuations = punctuationIndex.map(i => NORMAL_PUNCTUATION[i])

  password = password.split('').reduce((pwd, unitType) => {
    let char = ''
    switch (unitType) {
      case 'n':
        char = numbers.pop()
        break
      case 'c':
        char = chars.pop()
        break
      case 'p':
        char = punctuations.pop()
        break
      default:
    }
    return pwd + char
  }, '')
  return password
}

export function isArrayEqual(array1, array2, sort) {
  if (sort) {
    return array1.sort(sort).toString() === array2.sort(sort).toString()
  }
  return array1.sort().toString() === array2.sort().toString()
}
